﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;
using System.ComponentModel;
using System.Xml.Linq;
using System.Reflection;

namespace Objects
{
    public abstract partial class Valuehost : ICloneable, INotifyPropertyChanged,
        IAbsorber<string>,
        IAbsorber<Valuehost>,
        ICoalescable<Valuehost>,
        IDecoalescable<Valuehost>,
        ICompositable<Valuehost>,
        IDecompositable<Valuehost>
    {
        public static object operator +(Valuehost left, Valuehost right)
        {
            if (left != null)
                return left.Coalesce(right);
            else
                return right;
        }
        public static object operator *(Valuehost left, Valuehost right)
        {
            if (left != null)
                return left.Composite(right);
            else
                return right;
        }
        public static object operator -(Valuehost left, Valuehost right)
        {
            if (left != null)
                return left.Decoalesce(right);
            else
                return right;
        }
        public static object operator /(Valuehost left, Valuehost right)
        {
            if (left != null)
                return left.Decomposite(right);
            else
                return right;
        }

        public bool IsDirty = false;
        protected Valuehost()
        {
        }
        public static void Init()
        {
            InitParseFuncs();
        }
        /// <summary>
        /// Инъекция
        /// </summary>        
        public virtual bool Inject(Valuehost value)
        {
            ParseInjector pi;
            if ((pi = value as ParseInjector) != null)
            {
                Absorbe(pi.StringValue);
                return true;
            }
            else
                return false;
        }

        #region ICloneable Members
        public object Clone()
        {
            Valuehost val = null;
            Clone(ref val);
            return val;
        }
        protected abstract void Clone(ref Valuehost chain);
        
        public T CloneCastTo<T>()
        {
            return (T)Clone();
        }
        #endregion
        private static void InitParseFuncs()
        {
            ParseFunc.Add(typeof(Guid), (s) =>
            {
                return new Guid(s);
            });

            ParseFunc.Add(typeof(string), (s) => s);
        }

        public static Dictionary<Type, Func<string, object>> ParseFunc
            = new Dictionary<Type, Func<string, object>>();

        #region Implicit operators
        public static implicit operator Valuehost(string value)
        {
            return value.InjectParse();
        }
        public static implicit operator Valuehost(int value)
        {
            return value.InjectValue();
        }
        public static implicit operator Valuehost(double value)
        {
            return value.InjectValue();
        }
        public static implicit operator Valuehost(Guid value)
        {
            return value.InjectValue();
        }
        public static implicit operator Valuehost(DateTime value)
        {
            return value.InjectValue();
        }
        public static implicit operator Valuehost(TimeSpan value)
        {
            return value.InjectValue();
        }
        public static implicit operator Valuehost(bool value)
        {
            return value.InjectValue();
        }
        #endregion

        public abstract object Value { get; set; }
        

        #region INotifyPropertyChanged Members

        protected void OnPropertyChanged(string PropName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(PropName));
        }
        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        #region IAbsorber<string> Members

        public virtual object Absorbe(string val)
        {
            return this;
        }

        #endregion

        #region IAbsorber<Valuehost> Members

        public virtual object Absorbe(Valuehost val)
        {
            Inject(val);
            return this;
        }

        #endregion

        #region ICoalescable<Valuehost> Members

        public virtual object Coalesce(Valuehost val)
        {
            return this;
        }
        public virtual object Decoalesce(Valuehost val)
        {
            return this;
        }

        #endregion

        #region ICompositable<Valuehost> Members

        public virtual object Composite(Valuehost val)
        {
            return this;
        }
        public virtual object Decomposite(Valuehost val)
        {
            return this;
        }

        #endregion
    }

    public static partial class ValuehostExtension
    {
        public static T CloneAs<T>(this Valuehost vh)
            where T : class
        {
            if (vh != null)
                return vh.Clone() as T;
            else
                return default(T);
        }
        public static Valuehost Injection(this object obj)
        {
            string strk;
            Validator vli;
            if ((strk = obj as string) != null)
                return new ParseInjector(strk);
            else if ((vli = obj as Validator) != null)
                return new ValidInjector(vli);
            else
                return new ValueInjector(obj);
        }

        public static Valuehost InjectParse(this string strk)
        {
            return new ParseInjector(strk);
        }

        public static Valuehost InjectExt(this Valuehost obj1, Valuehost obj2)
        {
            if (obj1 == null && obj2 != null)
                return (Valuehost)obj2.Clone() ?? obj2;
            else if (obj1 == obj2 || (obj1 != null && obj2 == null))
                return obj1;
            else
            {
                obj1.Inject(obj2);
                return obj1;
            }
        }
    }

    [ValueConversion(typeof(Valuehost), typeof(string))]
    public class ValuedConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value != null)
                return value.ToString();
            else
                return null;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return (Valuehost)((string)value);
        }

        #endregion
    }
}
